/*
 * Created on Oct 19, 2003
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package auditoryTree;
import java.util.*;
import java.awt.geom.*;
//import java.awt.*;

/**
 * This class contain the information for the system to render the 
 * tree as a Sunburst representations
 * it contains layers for different levels of the tree, and ellipse for 
 * drawing, etc.
 * 
 * Also, I need to add marking menu's capability to this menu 
 * so, first, I need to render a smaller menu in the center that acts as marking
 * menu, and use speed to determine if this can be used or not. 
 * 
 * @author sszhao
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class TreeAudibleModel {
	private ArrayList[] moLayers;
	private int miMaxDepth;
	private Ellipse2D[] moCircles;
	
	private Ellipse2D moMarkingCircle; //this is the circle that cover the marking menu
	
	//this is a layer that we put the default behavior for the tree, it will render the marking
	//menu at the first level, and see how it will go
	private ArrayList moMarkingMenu;

	private boolean[] mbCircleSet; //this is used to determine if this circle is enabled or not, or we can 
									//draw the circle differently with the flag's status
	private TreeModel moModel;
	
	private TreeModel moMarkingModel;
	
	//Constructors
	private TreeAudibleModel(int depth) {
		moLayers = new ArrayList[depth];
		moCircles = new Ellipse2D[depth];
		mbCircleSet = new boolean[depth];
		miMaxDepth = depth;
		for (int i = 0; i < depth; i++) {
			moLayers[i] = new ArrayList();
			moCircles[i] = new Ellipse2D.Double();
			mbCircleSet[i] = false;
		}
		moMarkingMenu = new ArrayList();
		moMarkingCircle = new Ellipse2D.Double();
	}

	public TreeAudibleModel(TreeModel model, TreeModel markingModel) {
		this(model.maxDepth());
		moModel = model;
		moMarkingModel = markingModel;
		//setAllEnabled(true);
	}

	public void addShapeToLayer(int layerNo, AudibleMenuItem shape) {
		if (layerNo < 0 || layerNo > moLayers.length - 1) {
			return;
		} else {
			moLayers[layerNo].add(shape);
		}
	}

	public void addCircleToLayer(int layerNo, Ellipse2D shape) {
		if (layerNo < 0 || layerNo > moCircles.length - 1) {
			return;
		} else {
			moCircles[layerNo] = shape;
		}
	}
	
	public void addToMarkingMenu(AudibleMenuItem shape){
		moMarkingMenu.add(shape);
	}
	
	public ArrayList getMarkingMenu(){
		return moMarkingMenu;
	}

	public ArrayList getLayer(int layerNo) {
		if (layerNo < 0 || layerNo > moLayers.length - 1) {
			return null;
		} else {
			return moLayers[layerNo];
		}
	}

	public Ellipse2D getCircle(int circleNo) {
		if (circleNo < 0 || circleNo > moCircles.length - 1) {
			return null;
		} else {
			return moCircles[circleNo];
		}
	}
	/**
	 * @return
	 */
	public int getMaxDepth() {
		return miMaxDepth;
	}

	/**
	 * @return
	 */
	public TreeModel getModel() {
		return moModel;
	}

	/**
	 * @param i
	 */
	public void setMaxDepth(int i) {
		miMaxDepth = i;
	}

	/**
	 * @param model
	 */
	public void setModel(TreeModel model) {
		moModel = model;
	}

	public boolean getCircleSet(int no) {
		return mbCircleSet[no];
	}

	public void setCircleSet(int no, boolean value) {
		if (no >= 0 && no < mbCircleSet.length)
			mbCircleSet[no] = value;
	}

	

	/**
	 * This function will set certain levels specified to be enabled
	 * or not. Another approach will be setting specific angles to be
	 * enabled or not
	 * @param levels
	 * @param value
	 */
	public void setLevelsEnabled(int[] levels, boolean value) {
		for (int i = 0; i < moLayers.length; i++) {
			ArrayList layer = moLayers[i];
			if (intBelongsToArray(i, levels)) {

				for (int j = 0; j < layer.size(); j++) {
					AudibleMenuItem item = (AudibleMenuItem) layer.get(j);
					item.setEnabled(value);
				}
			}
		}
	}
	
	public void setAllEnabled(boolean value){
		for (int i = 0; i < moLayers.length; i++) {
			ArrayList layer = moLayers[i];	
			for (int j = 0; j < layer.size(); j++) {
				AudibleMenuItem item = (AudibleMenuItem) layer.get(j);
				item.setEnabled(value);
			}
		}
	}
	
	/**
	 * Check to see if the int belongs to this array or not
	 * this method is used in setLevelsEnabled to determine if a value
	 * belongs to the numbers in the array or not
	 * 
	 * @param i
	 * @param values
	 * @return
	 */
	public boolean intBelongsToArray(int i, int[] values){
	   Arrays.sort(values);
	   int index = Arrays.binarySearch(values, i);
		  if (index < 0) {
			  // not found
			  return false;
		  }
		  else{
		  	return true;
		  }
	}
	
	
		
	/**
	 * @return
	 */
	public Ellipse2D getMarkingCircle() {
		return moMarkingCircle;
	}

	/**
	 * @param ellipse2D
	 */
	public void setMarkingCircle(Ellipse2D ellipse2D) {
		moMarkingCircle = ellipse2D;
	}

	}
